/****************************************************************************************************************************
   RequestHandlerImpl.h - Dead simple web-server.
   For ESP8266 AT-command running shields

   ESP8266_AT_WebServer is a library for the ESP8266 AT-command shields to run WebServer
   Based on and modified from ESP8266 https://github.com/esp8266/Arduino/releases
   Built by Khoi Hoang https://github.com/khoih-prog/ESP8266_AT_WebServer
   Licensed under MIT license
   Version: 1.0.5

   Version Modified By   Date      Comments
   ------- -----------  ---------- -----------
    1.0.0   K Hoang      12/02/2020 Initial coding for Arduino Mega, Teensy, etc
    1.0.1   K Hoang      17/02/2020 Add support to server's lambda function calls
    1.0.2   K Hoang      22/02/2020 Add support to SAMD (DUE, ZERO, MKR, NANO_33_IOT, M0, M0 Pro, AdaFruit, etc) boards
    1.0.3   K Hoang      03/03/2020 Add support to STM32 (STM32,F0,F1, F2, F3, F4, F7, etc) boards
    1.0.4   K Hoang      19/03/2020 Fix bug. Sync with ESP8266WebServer library of core v2.6.3
    1.0.5   K Hoang      17/04/2020 Add support to SAMD51 and SAM DUE boards
 *****************************************************************************************************************************/

#ifndef RequestHandlerImpl_h
#define RequestHandlerImpl_h

#include "RequestHandler.h"
#include "mimetable.h"

class FunctionRequestHandler : public RequestHandler {
  public:
    FunctionRequestHandler(ESP8266_AT_WebServer::THandlerFunction fn, ESP8266_AT_WebServer::THandlerFunction ufn, const String &uri, HTTPMethod method)
      : _fn(fn)
      , _ufn(ufn)
      , _uri(uri)
      , _method(method)
    {
    }

    bool canHandle(HTTPMethod requestMethod, String requestUri) override  
    {
      if (_method != HTTP_ANY && _method != requestMethod)
        return false;

      if (requestUri == _uri)
        return true;

      if (_uri.endsWith("/*"))
      {
        String _uristart = _uri;
        _uristart.replace("/*", "");
        if (requestUri.startsWith(_uristart))
          return true;
      }

      return false;
    }

    bool canUpload(String requestUri) override  
    {
      if (!_ufn || !canHandle(HTTP_POST, requestUri))
        return false;

      return true;
    }

    bool handle(ESP8266_AT_WebServer& server, HTTPMethod requestMethod, String requestUri) override 
    {
      (void) server;
      
      if (!canHandle(requestMethod, requestUri))
        return false;

      LOGINFO(F("ReqHandler::handle"));

      _fn();

      LOGINFO(F("ReqHandler::handle done"));
      return true;
    }

    void upload(ESP8266_AT_WebServer& server, String requestUri, HTTPUpload& upload) override 
    {
      (void) server;
      (void) upload;
        
      if (canUpload(requestUri))
        _ufn();
    }

  protected:
    ESP8266_AT_WebServer::THandlerFunction _fn;
    ESP8266_AT_WebServer::THandlerFunction _ufn;
    String _uri;
    HTTPMethod _method;
};

class StaticRequestHandler : public RequestHandler 
{
  public:

    bool canHandle(HTTPMethod requestMethod, String requestUri) override  
    {
      //if (requestMethod != HTTP_GET)
      if ((requestMethod != HTTP_GET) && (requestMethod != HTTP_HEAD))
        return false;

      if ((_isFile && requestUri != _uri) || !requestUri.startsWith(_uri))
        return false;

      return true;
    }

    #if USE_NEW_WEBSERVER_VERSION
    
    static String getContentType(const String& path) 
    {
        using namespace mime;
        char buff[sizeof(mimeTable[0].mimeType)];
        // Check all entries but last one for match, return if found
        for (size_t i=0; i < sizeof(mimeTable)/sizeof(mimeTable[0])-1; i++) 
        {
            strcpy(buff, mimeTable[i].endsWith);
            if (path.endsWith(buff)) {
                strcpy(buff, mimeTable[i].mimeType);
                return String(buff);
            }
        }
        // Fall-through and just return default type
        strcpy(buff, mimeTable[sizeof(mimeTable)/sizeof(mimeTable[0])-1].mimeType);
        return String(buff);
    }
    
    #else
    static String getContentType(const String& path) {
      if (path.endsWith(".html")) return "text/html";
      else if (path.endsWith(".htm")) return "text/html";
      else if (path.endsWith(".css")) return "text/css";
      else if (path.endsWith(".txt")) return "text/plain";
      else if (path.endsWith(".js")) return "application/javascript";
      else if (path.endsWith(".png")) return "image/png";
      else if (path.endsWith(".gif")) return "image/gif";
      else if (path.endsWith(".jpg")) return "image/jpeg";
      else if (path.endsWith(".ico")) return "image/x-icon";
      else if (path.endsWith(".svg")) return "image/svg+xml";
      else if (path.endsWith(".ttf")) return "application/x-font-ttf";
      else if (path.endsWith(".otf")) return "application/x-font-opentype";
      else if (path.endsWith(".woff")) return "application/font-woff";
      else if (path.endsWith(".woff2")) return "application/font-woff2";
      else if (path.endsWith(".eot")) return "application/vnd.ms-fontobject";
      else if (path.endsWith(".sfnt")) return "application/font-sfnt";
      else if (path.endsWith(".xml")) return "text/xml";
      else if (path.endsWith(".pdf")) return "application/pdf";
      else if (path.endsWith(".zip")) return "application/zip";
      else if (path.endsWith(".gz")) return "application/x-gzip";
      else if (path.endsWith(".appcache")) return "text/cache-manifest";
      return "application/octet-stream";
    }
  #endif
  
  
  protected:
    String _uri;
    String _path;
    String _cache_header;
    bool _isFile;
    size_t _baseUriLength;
};


#endif //RequestHandlerImpl_h
